﻿//-----------------------------------------------------------------------------------------------------------
// WBFSSync Project by Omega Frost 
// http://wbfssync.codeplex.com/
//
// WBFSSync is Licensed under the terms of the 
// Microsoft Reciprocal License (Ms-RL)
//-----------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WBFSe3.Wbfs
{
    public class WbfsUsage
    {
        //------------------------------------------------------------------------------------------
        // Structs
        //------------------------------------------------------------------------------------------
        public struct REGION
        {
            public int Position;
            public bool Value;
        }


        //------------------------------------------------------------------------------------------
        // Variables
        //------------------------------------------------------------------------------------------
        private REGION[] rRegions;
        private int iCount;

        //------------------------------------------------------------------------------------------
        // Properties
        //------------------------------------------------------------------------------------------
        public Boolean this[int index]
        {
            get
            {
                int i = 0;
                while (index >= rRegions[i + 1].Position) i++;
                return rRegions[i].Value;
            }
        }

        public int Count
        {
            get
            {
                return iCount;
            }
        }

        //------------------------------------------------------------------------------------------
        // Routines
        //------------------------------------------------------------------------------------------

        //------------------------------------------------------------------------------------------
        // Constructor
        //------------------------------------------------------------------------------------------
        private WbfsUsage(WbfsUsage f)
        {
            rRegions = new REGION[f.rRegions.Length];
            f.rRegions.CopyTo(rRegions, 0);
            iCount = f.iCount;
        }


        //------------------------------------------------------------------------------------------
        // Constructor
        //------------------------------------------------------------------------------------------
        public WbfsUsage(Boolean[] bits)
        {
            iCount = bits.Length;

            // Conta o número de regiões
            int i, count = 1;
            for (i = 1; i < bits.Length; i++)
            {
                if (bits[i - 1] != bits[i])
                    count++;
            }

            // Cria as regiões
            rRegions = new REGION[count + 1];
            
            // Carrega as regiões
            bool state = !bits[0];
            int j = 0;
            for (i = 0; i < bits.Length; i++)
            {
                if (state != bits[i])
                {
                    state = bits[i];
                    rRegions[j].Position = i;
                    rRegions[j].Value = state;
                    j++;
                }
            }

            rRegions[count].Position = i;
            rRegions[count].Value = false;
        }


        //------------------------------------------------------------------------------------------
        // Duplicates the object
        //------------------------------------------------------------------------------------------
        public WbfsUsage Duplicate()
        {
            return new WbfsUsage(this);
        }


        //------------------------------------------------------------------------------------------
        // Copy the regions
        //------------------------------------------------------------------------------------------
        public REGION[] GetRegions()
        {
            REGION[] r = new REGION[rRegions.Length];
            rRegions.CopyTo(r, 0);
            return r;
        }


        //------------------------------------------------------------------------------------------
        // Count used sectors
        //------------------------------------------------------------------------------------------
        public int CountOnes()
        {
            int used = 0;
            int i;
            for (i = 0; i < rRegions.Length - 1; i++)
            {
                if (rRegions[i].Value)
                {
                    used += rRegions[i + 1].Position -
                        rRegions[i].Position;
                }
            }

            if (rRegions[i].Value)
            {
                used += iCount - rRegions[i].Position;
            }

            return used;
        }


        //------------------------------------------------------------------------------------------
        // Count free sectors
        //------------------------------------------------------------------------------------------
        public int CountZeroes()
        {
            int free = 0;
            int i;
            for (i = 0; i < rRegions.Length - 1; i++)
            {
                if (!rRegions[i].Value)
                {
                    free += rRegions[i + 1].Position -
                        rRegions[i].Position;
                }
            }

            if (!rRegions[i].Value)
            {
                free += iCount - rRegions[i].Position;
            }

            return free;
        }


        //------------------------------------------------------------------------------------------
        // Get the last used sector
        //------------------------------------------------------------------------------------------
        public int GetLastOne()
        {
            if (rRegions[rRegions.Length - 1].Value)
                return iCount - 1;

            for (int i = rRegions.Length - 2; i >= 0; i--)
            {
                if (rRegions[i].Value)
                    return rRegions[i + 1].Position - 1;
            }

            //Error
            return -1;
        }
    }
}
